package TCPTerminal

import (
	"bytes"
	"compress/zlib"
	"crypto/cipher"
	"crypto/des"
	"encoding/binary"
	"fmt"
	"io"
	"log"
	"net"
	"os"
	"sync"
)

const (
	PACKET_FLAG_COMPRESS = 1 //压缩
	PACKET_FLAG_ENCRYPT  = 2 //加密
	PHLEN                = 3 //包头长度
	COMPRESS_LEVEL       = 6
	MIN_COMPRESS_SIZE    = 48
)

type TCPTerminal struct {
	sock       *net.TCPConn
	connected  bool
	netRecvBuf bytes.Buffer
	netSndBuf  bytes.Buffer
	block      cipher.Block
	mu         sync.Mutex
	recvByteQ  chan<- []byte //接收到的完整数据包
	sendByteQ  <-chan []byte //准备发送的数据包
}

//NewTCPTerminal 创建TCP连接
func NewTCPTerminal(recvC, sendC chan []byte) *TCPTerminal {
	//ConvertdecKey()
	t := TCPTerminal{connected: false, recvByteQ: recvC, sendByteQ: sendC}
	var err error
	t.block, err = des.NewCipher(desSecKey)
	if err != nil {
		log.Println(err)
		return nil
	}
	return &t
}

//StartConnect 尝试连接服务器
func (t *TCPTerminal) StartConnect(addr string, port int) (netErr error) {

	tmp := fmt.Sprintf("%s:%d", addr, port)
	tcpAddr, netErr := net.ResolveTCPAddr("tcp4", tmp)

	if netErr != nil {
		t.CloseTerminal()
		return
	}

	t.sock, netErr = net.DialTCP("tcp", nil, tcpAddr)

	if netErr != nil {
		t.CloseTerminal()
		return
	}
	t.sock.SetNoDelay(true)
	t.connected = true

	go t.RecvData()
	go t.SendData()

	return
}

//ParsePacketHead 解析头部数据
func (t *TCPTerminal) ParsePacketHead(head [3]byte) (flag byte, dataLen uint16) {

	flag = byte(head[0])
	dataLen = binary.LittleEndian.Uint16(head[1:3])

	return
}

//---------------压缩/解压---------------
func uncompress(compressSrc []byte) []byte {
	b := bytes.NewReader(compressSrc)
	r, err := zlib.NewReader(b)
	if err != nil {
		log.Println("解压失败", err)
		return compressSrc
	}
	var out bytes.Buffer
	io.Copy(&out, r)
	return out.Bytes()
}

//--------------------------------------

//---------------加密/解密---------------
func sizeMod8(len uint16) uint16 {
	return (len + 7) / 8 * 8
}

var desSecKey = []byte{95, 27, 5, 20, 131, 4, 8, 88}

func (t *TCPTerminal) decryptNetData(netBytes []byte) []byte {
	var buf bytes.Buffer
	end := 8
	for start := 0; start < len(netBytes); start += 8 {
		tmp := make([]byte, 8)
		t.block.Decrypt(tmp, netBytes[start:end])
		buf.Write(tmp)
		end += 8
	}
	return buf.Bytes()
}

//--------------------------------------

//ParsePacketBody 解密,解压数据包
func (t *TCPTerminal) ParsePacketBody(flag byte, body []byte, originLen uint16) []byte {
	var originData []byte
	if flag&PACKET_FLAG_ENCRYPT == PACKET_FLAG_ENCRYPT {
		originData = t.decryptNetData(body)
	} else {
		originData = body
	}

	if flag&PACKET_FLAG_COMPRESS == PACKET_FLAG_COMPRESS {
		originData = uncompress(originData)
		originLen = uint16(len(originData))
	}

	return originData[:originLen]
}

func saveErrorNetData(data []byte) {
	outputFile, err := os.OpenFile("netdata", os.O_WRONLY|os.O_CREATE, 0666)
	if err != nil {
		log.Println("打开文件netdata错误 ", err)
		return
	}
	defer outputFile.Close()

	_, err = outputFile.Write(data)
	if err != nil {
		log.Println("打开文件netdata错误 ", err)
		return
	}
	log.Println("写入错误数据成功")
}

//IsConnect 是否保持连接
func (t *TCPTerminal) IsConnect() bool {
	return t.connected
}

//CloseTerminal 关闭连接
func (t *TCPTerminal) CloseTerminal() {
	t.mu.Lock()
	defer t.mu.Unlock()
	//可能别的地方调用关闭,确保这里只被调用一次
	if t.connected {
		t.sock.Close()
		t.connected = false
	}

}

//RecvData 只保证接收到完整网络包
func (t *TCPTerminal) RecvData() {
	//log.Println("RecvData start")
	for true {
		//接收包头
		head, err := t.RecvHead()
		if err != nil {
			t.CloseTerminal()
			break
		}
		//解析包头信息
		flag, originLen := t.ParsePacketHead(head)
		//接收包体
		body, err := t.RecvBody(originLen)
		if err != nil {
			t.CloseTerminal()
			break
		}
		//解析包体
		t.recvByteQ <- t.ParsePacketBody(flag, body, originLen)
	}
	close(t.recvByteQ)
	//log.Println("RecvData stop")
}

//RecvHead 收三字节包头
func (t *TCPTerminal) RecvHead() (head [3]byte, neterr error) {
	index := 0
	num := 0
	for true {
		num, neterr = t.sock.Read(head[index:])
		if neterr != nil {
			//log.Printf("RecvHead 中断开连接 原因 %v\n", neterr)
			break
		}
		//统计接收到字符
		index += num
		if index < 3 {
			//包头读取不完整
			continue
		}
		if index >= 3 {
			//读取完整
			break
		}
	}
	return
}

//RecvBody 接收包体
func (t *TCPTerminal) RecvBody(dataLen uint16) ([]byte, error) {
	//包体长度一定是8的倍数,因为和DES加密有关
	dataLen = sizeMod8(dataLen)
	body := make([]byte, dataLen)
	index := 0
	var neterr error
	for true {
		num, neterr := t.sock.Read(body[index:])
		if neterr != nil {
			//log.Println("RecvBody failed ", neterr)
			break
		}
		index += num
		if num < int(dataLen) {
			continue
		}
		if num >= int(dataLen) {
			break
		}
	}
	return body, neterr
}

//SendData 只保证发送完整数据
func (t *TCPTerminal) SendData() {
	//log.Println("SendData start")
	for true {

		data, ok := <-t.sendByteQ
		if !ok {
			//channel被关闭
			//log.Println("sendByteQ be closed")
			break
		}

		index := 0
		total := len(data)
		if !t.IsConnect() {
			break
		}

		for true {
			num, err := t.sock.Write(data[index:])
			if err != nil {
				//错误处理
				log.Println(err)
				t.CloseTerminal()
				break
			}

			index += num

			if index == total {
				//协议完整发送
				break
			}

			if num < total {
				//发送长度不足
				continue
			}
		}
	}
	//log.Println("SendData stop")
}
